package pkgscanner;

import pkgscanner.annotations.Component;
import pkgscanner.enums.BeanTypeEnum;
import pkgscanner.filter.AnnotationScanFilter;
import pkgscanner.filter.ScanFilter;
import pkgscanner.util.StringUtils;

import java.io.File;
import java.util.*;

/**
 * @author 星环
 * @date 2023/3/9 16:54:21
 * @description
 */
public class SimplePackageScanner implements PackageScanner{
    ScanFilter filter;
    String path;
    public SimplePackageScanner(String path){
        this.path = path;
        filter = new AnnotationScanFilter();
    }


    @Override
    public Set<BeanDefinition> doScan() {
        String packagePath = StringUtils.packageNameToRealPath(path,true);
        File file = new File(packagePath);
        if(!file.exists()){
            return null;
        }
        Set<BeanDefinition> beanDefinitions = null;
        try {
            beanDefinitions = recusiveScan(file);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return beanDefinitions;
    }

    private Set<BeanDefinition> recusiveScan(File file) throws Exception {
        Set<BeanDefinition> beanDefinitions = new HashSet<>();
        Queue<File> fileQueue = new LinkedList<>();

        fileQueue.add(file);
        while (!fileQueue.isEmpty()){
            File f = fileQueue.remove();
            if(f.isDirectory()){
                File[] files = f.listFiles();
                fileQueue.addAll(Arrays.asList(Objects.requireNonNull(files)));
            }else {
                if(f.getName().endsWith(".class")){
                    String classFullName = StringUtils.realPathToClassFullName(f.getPath());
                    Class<?> aClass = SimplePackageScanner.class.getClassLoader().loadClass(classFullName);
                    BeanDefinition beanDefinition = createBeanDefByClazz(aClass);
                    if(beanDefinition != null) {
                        beanDefinitions.add(beanDefinition);
                    }
                }
            }
        }
        return beanDefinitions;
    }

    private BeanDefinition createBeanDefByClazz(Class<?> aClass) throws Exception {
        if(aClass == null){
            return null;
        }
        Component isBeanAnno = aClass.getAnnotation(Component.class);
        if(isBeanAnno == null){
            return null;
        }
        BeanDefinition beanDef = new BeanDefinition();
        String value = isBeanAnno.value();
        beanDef.beanType = isBeanAnno.type();
        char ch = aClass.getSimpleName().charAt(0);
        beanDef.name = isBeanAnno.value();
        if("".equals(beanDef.name)){
            beanDef.name = Character.toLowerCase(ch) + aClass.getSimpleName().substring(1);
        }
        beanDef.clazz = aClass;
        if(isBeanAnno.type().equals(BeanTypeEnum.SINGLETON)){
            beanDef.bean = aClass.getConstructor(null).newInstance();
        }else {
            beanDef.constructor = aClass.getConstructor(null);
        }
        return beanDef;
    }
}
